package sch.frog.utils;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.util.ArrayList;
import java.util.List;

/**
 * 文件操作工具类
 * 
 */
public class FileUtil {

	// ==============================增====================================
	/**
	 * 创建单个文件
	 * 
	 * @param descFileName 文件名，包含路径
	 * @return 如果创建成功，则返回true，否则返回false
	 * @throws IOException
	 */
	public static boolean createFile(String descFileName) throws IOException {
		File file = new File(descFileName);
		if (file.exists()) {
			throw new IOException("文件已存在");
		}
		if (descFileName.endsWith(File.separator)) {
			throw new IOException("非法的文件名");
		}
		if (!file.getParentFile().exists()) {
			// 如果文件所在的目录不存在，则创建目录
			throw new IOException("指定路径不存在");
		}

		// 创建文件
		if (file.createNewFile()) {
			return true;
		} else {
			return false;
		}
	}

	/**
	 * 创建目录
	 * 
	 * @param descDirName 目录名,包含路径
	 * @return 如果创建成功，则返回true，否则返回false
	 * @throws IOException
	 */
	public static boolean createDirectory(String descDirName) throws IOException {
		String descDirNames = descDirName;
		if (!descDirNames.endsWith(File.separator)) {
			descDirNames = descDirNames + File.separator;
		}
		File descDir = new File(descDirNames);
		if (descDir.exists()) {
			throw new IOException("目录已存在");
		}
		// 创建目录
		if (descDir.mkdirs()) {
			return true;
		} else {
			return false;
		}

	}

	/**
	 * 复制单个文件
	 * 
	 * @param srcFileName  待复制的文件名
	 * @param descFileName 目标文件名
	 * @param coverlay     如果目标文件已存在，是否覆盖
	 * @return 如果复制成功，则返回true，否则返回false
	 * @throws IOException
	 */
	public static boolean copyFile(String srcFileName, String descFileName, boolean coverlay) throws IOException {
		File srcFile = new File(srcFileName);
		// 判断源文件是否存在
		if (!srcFile.exists()) {
			throw new IOException("源文件不存在");
		}
		// 判断源文件是否是合法的文件
		else if (!srcFile.isFile()) {
			throw new IOException("目标不是文件");
		}
		File descFile = new File(descFileName);
		// 判断目标文件是否存在
		if (descFile.exists()) {
			// 如果目标文件存在，并且允许覆盖
			if (coverlay) {
				if (!FileUtil.deleteFiles(descFileName)) {
					throw new IOException("目标文件删除失败");
				}
			} else {
				throw new IOException("目标文件已存在");
			}
		} else {
			if (!descFile.getParentFile().exists()) {
				// 创建目标文件所在的目录
				if (!descFile.getParentFile().mkdirs()) {
					throw new IOException("目录创建失败");
				}
			}
		}

		// 准备复制文件
		// 读取的位数
		int readByte = 0;
		InputStream ins = null;
		OutputStream outs = null;
		try {
			// 打开源文件
			ins = new FileInputStream(srcFile);
			// 打开目标文件的输出流
			outs = new FileOutputStream(descFile);
			byte[] buf = new byte[1024];
			// 一次读取1024个字节，当readByte为-1时表示文件已经读取完毕
			while ((readByte = ins.read(buf)) != -1) {
				// 将读取的字节流写入到输出流
				outs.write(buf, 0, readByte);
			}
			return true;
		} catch (IOException e) {
			throw e;
		} finally {
			// 关闭输入输出流，首先关闭输出流，然后再关闭输入流
			if (outs != null) {
				try {
					outs.close();
				} catch (IOException oute) {
					oute.printStackTrace();
				}
			}
			if (ins != null) {
				try {
					ins.close();
				} catch (IOException ine) {
					ine.printStackTrace();
				}
			}
		}
	}

	/**
	 * 复制整个目录的内容
	 * 
	 * @param srcDirName  源目录名
	 * @param descDirName 目标目录名
	 * @param coverlay    如果目标目录存在，是否覆盖
	 * @return 如果复制成功返回true，否则返回false
	 * @throws IOException
	 */
	public static boolean copyDirectory(String srcDirName, String descDirName, boolean coverlay)
			throws IOException {
		File srcDir = new File(srcDirName);
		// 判断源目录是否存在
		if (!srcDir.exists()) {
			throw new IOException("找不到指定的目录");
		}
		// 判断源目录是否是目录
		else if (!srcDir.isDirectory()) {
			throw new IOException("指定路径不是目录");
		}
		// 如果目标文件夹名不以文件分隔符结尾，自动添加文件分隔符
		String descDirNames = descDirName;
		if (!descDirNames.endsWith(File.separator)) {
			descDirNames = descDirNames + File.separator;
		}
		File descDir = new File(descDirNames);
		// 如果目标文件夹存在
		if (descDir.exists()) {
			if (coverlay) {
				// 允许覆盖目标目录
				if (!FileUtil.deleteFiles(descDirNames)) {
					return false;
				}
			} else {
				new IOException("目录已存在");
				return false;
			}
		} else {
			// 创建目标目录
			if (!descDir.mkdirs()) {
				return false;
			}

		}

		boolean flag = true;
		// 列出源目录下的所有文件名和子目录名
		File[] files = srcDir.listFiles();
		for (int i = 0; i < files.length; i++) {
			// 如果是一个单个文件，则直接复制
			if (files[i].isFile()) {
				flag = FileUtil.copyFile(files[i].getAbsolutePath(), descDirName + files[i].getName(), false);
				// 如果拷贝文件失败，则退出循环
				if (!flag) {
					break;
				}
			}
			// 如果是子目录，则继续复制目录
			if (files[i].isDirectory()) {
				flag = FileUtil.copyDirectory(files[i].getAbsolutePath(), descDirName + files[i].getName(), false);
				// 如果拷贝目录失败，则退出循环
				if (!flag) {
					break;
				}
			}
		}

		if (!flag) {
			return false;
		}

		return true;
	}

	
	// ==============================================删=======================================
	/**
	 * 
	 * 删除文件，可以删除单个文件或文件夹
	 * 
	 * @param path 被删除的文件名
	 * @return 如果删除成功，则返回true，否是返回false
	 * @throws IOException
	 */
	public static boolean deleteFiles(String path) throws IOException {
		File file = new File(path);
		if (!file.exists()) {
			return true;
		} else {
			if (file.isFile()) {
				return FileUtil.deleteFile(path);
			} else {
				return FileUtil.deleteDirectory(path);
			}
		}
	}

	/**
	 * 
	 * 删除单个文件
	 * 
	 * @param fileName 被删除的文件名
	 * @return 如果删除成功，则返回true，否则返回false
	 * @throws IOException
	 */
	public static boolean deleteFile(String fileName) throws IOException {
		File file = new File(fileName);
		if (file.exists() && file.isFile()) {
			if (file.delete()) {
				return true;
			} else {
				return false;
			}
		} else {
			throw new IOException("文件不存在");
		}
	}

	/**
	 * 
	 * 删除目录及目录下的文件
	 * 
	 * @param dirName 被删除的目录所在的文件路径
	 * @return 如果目录删除成功，则返回true，否则返回false
	 * @throws IOException
	 */
	public static boolean deleteDirectory(String dirName) throws IOException {
		String dirNames = dirName;
		if (!dirNames.endsWith(File.separator)) {
			dirNames = dirNames + File.separator;
		}
		File dirFile = new File(dirNames);
		if (!dirFile.exists() || !dirFile.isDirectory()) {
			throw new IOException("找不到指定的目录");
		}
		boolean flag = true;
		// 列出全部文件及子目录
		File[] files = dirFile.listFiles();
		for (int i = 0; i < files.length; i++) {
			// 删除子文件
			if (files[i].isFile()) {
				flag = FileUtil.deleteFile(files[i].getAbsolutePath());
				// 如果删除文件失败，则退出循环
				if (!flag) {
					break;
				}
			}
			// 删除子目录
			else if (files[i].isDirectory()) {
				flag = FileUtil.deleteDirectory(files[i].getAbsolutePath());
				// 如果删除子目录失败，则退出循环
				if (!flag) {
					break;
				}
			}
		}

		if (!flag) {
			return false;
		}
		// 删除当前目录
		if (dirFile.delete()) {
			return true;
		} else {
			return false;
		}

	}

	// =================================================查============================================
	/**
	 * 获取文件夹下的文件
	 * 
	 * @param strPath   文件夹路径
	 * @param recursion 是否递归获取子文件夹内的文件
	 * @param suffixs   指定文件后缀
	 * @return
	 */
	public static List<File> getFileList(String strPath, boolean recursion, String... suffixs) {
		List<File> filelist = new ArrayList<File>();
		File dir = new File(strPath);
		File[] files = dir.listFiles(); // 该文件目录下文件全部放入数组
		if (files != null) {
			for (int i = 0; i < files.length; i++) {
				String fileName = files[i].getName();
				if (files[i].isDirectory()) { // 判断是文件还是文件夹
					if (recursion) {
						List<File> childList = getFileList(files[i].getAbsolutePath(), recursion, suffixs); // 获取文件绝对路径
						filelist.addAll(childList);
					}
					continue;
				} else if (suffixs != null && suffixs.length > 0) {
					for (String suffix : suffixs) {
						if (fileName.endsWith(suffix)) {
							filelist.add(files[i]);
							break;
						}
					}
				} else {
					filelist.add(files[i]);
				}
			}
		}
		return filelist;
	}

	// =========================================改=============================
	/**
	 * 向文件中写入内容
	 * @param path 文件路径
	 * @param content	文件内容
	 * @param append	是否追加
	 * @throws IOException
	 */
	public static void writeToFile(String path, String content, boolean append) throws IOException {
		writeToFile(path, content, null, append);
	}

	/**
	 * 向文件中写入内容
	 * @param path	文件路径
	 * @param content	文件内容
	 * @param encoding	内容的字符编码
	 * @param append	是否追加
	 * @throws IOException
	 */
	public static void writeToFile(String path, String content, String encoding, boolean append) throws IOException {
		File file = new File(path);
		OutputStream outputStream = new FileOutputStream(file, append);
		if (encoding != null)
			outputStream.write(content.getBytes(encoding));
		else
			outputStream.write(content.getBytes());
		outputStream.close();
	}

	/**
	 * 向文件中写入内容
	 * @param path	文件路径
	 * @param name	文件名
	 * @param content	文件内容
	 * @param encoding	内容的字符编码
	 * @param append 是否追加
	 * @return
	 * @throws IOException
	 */
	public static File writeToFile(String path, String name, String content, String encoding, boolean append)
			throws IOException {
		File dir = new File(path);
		if (!dir.exists()) {
			dir.mkdirs();
		}
		File file = new File(path, name);
		try (OutputStreamWriter fw = encoding == null ? new OutputStreamWriter(new FileOutputStream(file, append))
				: new OutputStreamWriter(new FileOutputStream(file, append), encoding);
				BufferedWriter bw = new BufferedWriter(fw)) {
			bw.write(content, 0, content.length());
			bw.flush();
		} catch (IOException e) {
			throw e;
		}

		return file;
	}
	
	/**
	 * 修复路径，将 \\ 或 / 等替换为 File.separator
	 * 
	 * @param path
	 * @return
	 */
	public static String pathRepair(String path) {
		StringBuilder sb = new StringBuilder();
		for (int i = 0; i < path.length(); i++) {
			char ch = path.charAt(i);
			if (ch == '\\' || ch == '/') {
				sb.append(File.separator);
			} else {
				sb.append(ch);
			}
		}
		return sb.toString();
	}

}
